#include "Avalon/ServiceLocator/ServiceLocatorServlet.hpp"
#include <boost/lexical_cast.hpp>
#include <cryptopp/hex.h>
#include <cryptopp/osrng.h>
#include <cryptopp/sha.h>
#include "Avalon/Base/Algorithm.hpp"
#include "Avalon/ServiceLocator/Account.hpp"
#include "Avalon/ServiceLocator/ServiceLocatorChannel.hpp"
#include "Avalon/ServiceLocator/ServiceLocatorDataStore.hpp"

using namespace Avalon;
using namespace Avalon::ServiceLocator;
using namespace Avalon::Services;
using namespace Avalon::Threading;
using namespace boost;
using namespace boost::posix_time;
using namespace CryptoPP;
using namespace std;

Initializer<ServiceLocatorServlet>::Initializer(
    ServiceLocator::ServiceLocatorDataStore* dataStore)
    : m_dataStore(dataStore) {}

struct ServiceLocatorServlet::ServiceEntryListing {
  vector<ServiceEntry> m_entries;
  vector<ServiceLocatorChannel*> m_subscribers;
};

struct ServiceLocatorServlet::SubscriberEntry {
  DirectoryEntry::Tag m_tag;
  vector<ServiceLocatorChannel*> m_subscribers;

  SubscriberEntry(const DirectoryEntry::Tag& tag)
      : m_tag(tag) {}
};

ServiceLocatorServlet::ServiceLocatorServlet(
    const Initializer<ServiceLocatorServlet>& initializer)
    : m_dataStore(initializer.m_dataStore),
      m_nextServiceId(1) {
  SetHandler<LoginService>(bind(&ServiceLocatorServlet::OnLoginRequest, this,
    _1, _2, _3));
  SetHandler<RegisterService>(bind(&ServiceLocatorServlet::OnRegisterRequest,
    this, _1, _2, _3));
  SetHandler<UnregisterService>(bind(
    &ServiceLocatorServlet::OnUnregisterRequest, this, _1, _2));
  SetHandler<LocateService>(bind(&ServiceLocatorServlet::OnLocateRequest, this,
    _1, _2));
  SetHandler<SubscribeAvailabilityService>(bind(
    &ServiceLocatorServlet::OnSubscribeRequest, this, _1, _2));
  SetHandler<UnsubscribeAvailabilityService>(bind(
    &ServiceLocatorServlet::OnUnsubscribeRequest, this, _1, _2));
  SetHandler<LoadDirectoryEntryService>(bind(
    &ServiceLocatorServlet::OnLoadDirectoryEntryRequest, this, _1, _2));
  SetHandler<LoadParentDirectoryService>(bind(
    &ServiceLocatorServlet::OnLoadParentDirectoryRequest, this, _1, _2));
  SetHandler<CreateAccountService>(bind(
    &ServiceLocatorServlet::OnCreateAccountRequest, this, _1, _2, _3, _4));
  SetHandler<CreateDirectoryService>(bind(
    &ServiceLocatorServlet::OnCreateDirectoryRequest, this, _1, _2, _3));
  SetHandler<MoveEntryService>(bind(&ServiceLocatorServlet::OnMoveEntryRequest,
    this, _1, _2, _3));
  SetHandler<DeleteEntryService>(bind(
    &ServiceLocatorServlet::OnDeleteEntryRequest, this, _1, _2));
  SetHandler<SetPermissionsService>(bind(
    &ServiceLocatorServlet::OnSetPermissionsRequest, this, _1, _2, _3, _4));
  SetHandler<SessionAuthenticationService>(bind(
    &ServiceLocatorServlet::OnSessionAuthenticationRequest, this, _1, _2, _3));
}

ServiceLocatorServlet::~ServiceLocatorServlet() {}

#if 0
void ServiceLocatorServlet::Open() {
  boost::lock_guard<boost::mutex> lock(m_mutex);
  if(m_isOpen) {
    return;
  }
  m_protocolServer.Open();
  bool isOpen;
  m_dataStore->SetClosedSlot(bind(&ServiceLocatorServlet::OnDataStoreClosed,
    this), Store(isOpen));
  m_dataStore->Open();
  m_dataStoreState.Initialize(true);
  int accountCount = m_dataStore->LoadAccountCount();
  if(accountCount == 0) {
    unsigned int directoryId = m_dataStore->CreateDirectory("*",
      DirectoryEntry::Tag(DirectoryEntry::Type::DIRECTORY, -1, ""));
    unsigned int accountId = m_dataStore->CreateAccount("root",
      DirectoryEntry::Tag(DirectoryEntry::Type::DIRECTORY, directoryId, "*"));
    m_dataStore->SetPassword(accountId, ComputeSHA(lexical_cast<string>(
      accountId)));
    m_dataStore->SetPermissions(accountId, directoryId,
      Directory::Permission::ALL);
  }
}

void ServiceLocatorServlet::Close() {
  ServerMixin::Close();
}

void ServiceLocatorServlet::HandleClose() {
  boost::lock_guard<boost::mutex> lock(m_mutex);
  if(m_dataStoreState.IsOpen()) {
    m_dataStore->Close();
    return;
  }
}

void ServiceLocatorServlet::HandleCloseClient(ServiceLocatorChannel* channel) {
  const vector<ServiceEntry>& registeredServices =
    channel->GetRegisteredServices();
  for(vector<ServiceEntry>::const_iterator i = registeredServices.begin();
      i != registeredServices.end(); ++i) {
    ServiceEntryListing& listing = m_serviceListings[i->GetName()];
    Remove(listing.m_entries, *i);
    ServiceAvailabilityMessage serviceMessage(*i, false);
    SendMessage(listing.m_subscribers, serviceMessage);
  }
  const set<DirectoryEntry::Tag>& entrySubscriptions =
    channel->GetDirectoryEntrySubscriptions();
  while(!entrySubscriptions.empty()) {
    const DirectoryEntry::Tag& tag = *entrySubscriptions.begin();
    map<unsigned int, SubscriberEntry>::iterator subscriberIterator =
      m_subscriptions.find(tag.m_id);
    assert(subscriberIterator != m_subscriptions.end());
    SubscriberEntry& subscriptions = subscriberIterator->second;
    Remove(subscriptions.m_subscribers, channel);
    channel->RemoveDirectoryEntrySubscription(tag);
    if(subscriptions.m_subscribers.empty()) {
      m_subscriptions.erase(subscriberIterator);
    }
  }
  const vector<string>& serviceSubscriptions =
    channel->GetServiceSubscriptions();
  for(vector<string>::const_iterator i = serviceSubscriptions.begin();
      i != serviceSubscriptions.end(); ++i) {
    ServiceEntryListing& listing = m_serviceListings[*i];
    Remove(listing.m_subscribers, channel);
  }
  m_sessions.erase(channel->GetSessionId());
}
#endif
void ServiceLocatorServlet::DeleteEntry(const DirectoryEntry::Tag& tag,
    const DirectoryEntry::Tag& parent) {
  if(tag.m_type == DirectoryEntry::Type::ACCOUNT) {
    return m_dataStore->DeleteAccount(tag.m_id);
  } else {
    vector<DirectoryEntry::Tag> entries = m_dataStore->LoadDirectoryEntries(
      tag.m_id);
    for(vector<DirectoryEntry::Tag>::const_iterator i = entries.begin();
        i != entries.end(); ++i) {
      DeleteEntry(*i, tag);
    }
    m_dataStore->DeleteDirectory(tag.m_id);
  }
  PublishDirectoryEntryMoved(tag, parent, false);
}

void ServiceLocatorServlet::PublishDirectoryEntryMoved(
    const DirectoryEntry::Tag& tag, const DirectoryEntry::Tag& parent,
    bool added) {
  map<unsigned int, SubscriberEntry>::const_iterator subscriberIterator =
    m_subscriptions.find(parent.m_id);
  if(subscriberIterator == m_subscriptions.end()) {
    return;
  }
  DirectoryEntryMovedMessage message(tag, parent, added);
  const SubscriberEntry& subscribers = subscriberIterator->second;
  SendMessage(subscribers.m_subscribers, message);
}

bool ServiceLocatorServlet::HasPermission(unsigned int account,
    unsigned int directory, Directory::Permission permission) {
  Directory::Permission accountPermissions =
    m_dataStore->LoadAccountPermissions(account, directory);
  if((accountPermissions & permission) == permission) {
    return true;
  }
  DirectoryEntry::Tag parent = m_dataStore->LoadParentTag(directory);
  if(parent.m_id == -1) {
    return false;
  }
  return HasPermission(account, parent.m_id, permission);
}

void ServiceLocatorServlet::OnDataStoreClosed() {
  boost::lock_guard<boost::mutex> lock(m_mutex);
  m_dataStoreState.SetClosed();
// TODO  Shutdown();
}

// TODO void ServiceLocatorServlet::OnServerConnectionClosed() {
//  boost::lock_guard<boost::mutex> lock(m_mutex);
//  CloseResources();
//}

void ServiceLocatorServlet::OnLoginRequest(
    const RequestToken<LoginService>& request, const string& username,
    const string& password) {
  ServiceLocatorChannel* channel = static_cast<ServiceLocatorChannel*>(
    request.GetChannel());
  if(channel->IsLoggedIn()) {
    request.SendResponse(make_tuple(false, "Account is already logged in.",
      DirectoryEntry::Tag(), ""));
    return;
  }
  try {
    DirectoryEntry::Tag account = m_dataStore->LoadAccountTag(username);
    if(account.m_id == -1) {
      request.SendResponse(make_tuple(false, "Invalid username or password.",
        DirectoryEntry::Tag(), ""));
      return;
    }
    string accountPassword = m_dataStore->LoadPassword(account.m_id);
    string receivedPassword = ComputeSHA(lexical_cast<string>(account.m_id) +
      password);
    if(accountPassword != receivedPassword) {
      request.SendResponse(make_tuple(false, "Invalid username or password.",
        DirectoryEntry::Tag(), ""));
      return;
    }
    string sessionId;
    {
      boost::lock_guard<boost::mutex> lock(m_mutex);
      do {
        sessionId = GenerateSessionId();
      } while(m_sessions.find(sessionId) != m_sessions.end());
      m_sessions.insert(make_pair(sessionId, channel));
    }
    channel->SetAccount(account);
    channel->SetSessionId(sessionId);
    request.SendResponse(make_tuple(true, "", account, sessionId));
  } catch(std::exception& e) {
    request.SendResponse(make_tuple(false, e.what(), DirectoryEntry::Tag(),
      ""));
  }
}

void ServiceLocatorServlet::OnRegisterRequest(
    const RequestToken<RegisterService>& request, const string& name,
    const string& details) {
  ServiceLocatorChannel* channel = static_cast<ServiceLocatorChannel*>(
    request.GetChannel());
  if(!channel->IsLoggedIn()) {
    request.SendResponse(make_tuple(false, "Not logged in.", ServiceEntry()));
    return;
  }
  boost::lock_guard<boost::mutex> lock(m_mutex);
  int id = m_nextServiceId;
  ++m_nextServiceId;
  ServiceEntry entry(name, details, id, channel->GetAccount());
  ServiceEntryListing& listing = m_serviceListings[name];
  listing.m_entries.push_back(entry);
  m_serviceEntries.insert(make_pair(id, entry));
  channel->RegisterService(entry);
  ServiceAvailabilityMessage serviceMessage(entry, true);
  SendMessage(listing.m_subscribers, serviceMessage);
  request.SendResponse(make_tuple(true, "", entry));
}

void ServiceLocatorServlet::OnUnregisterRequest(
    const RequestToken<UnregisterService>& request, int serviceId) {
  ServiceLocatorChannel* channel = static_cast<ServiceLocatorChannel*>(
    request.GetChannel());
  if(!channel->IsLoggedIn()) {
    request.SendResponse(make_tuple(false, "Not logged in."));
    return;
  }
  const vector<ServiceEntry>& registeredServices =
    channel->GetRegisteredServices();
  bool serviceFound = false;
  for(vector<ServiceEntry>::const_iterator i = registeredServices.begin();
      i != registeredServices.end(); ++i) {
    if(i->GetId() == serviceId) {
      serviceFound = true;
      break;
    }
  }
  if(!serviceFound) {
    request.SendResponse(make_tuple(false, "Service not found."));
    return;
  }
  boost::lock_guard<boost::mutex> lock(m_mutex);
  const ServiceEntry& entry = m_serviceEntries[serviceId];
  ServiceEntryListing& listing = m_serviceListings[entry.GetName()];
  Remove(listing.m_entries, entry);
  channel->UnregisterService(serviceId);
  ServiceAvailabilityMessage serviceMessage(entry, false);
  SendMessage(listing.m_subscribers, serviceMessage);
  request.SendResponse(make_tuple(true, ""));
}

void ServiceLocatorServlet::OnLocateRequest(
    const RequestToken<LocateService>& request, const string& name) {
  ServiceLocatorChannel* channel = static_cast<ServiceLocatorChannel*>(
    request.GetChannel());
  if(!channel->IsLoggedIn()) {
    request.SendResponse(make_tuple(false, "Not logged in.",
      vector<ServiceEntry>()));
    return;
  }
  boost::lock_guard<boost::mutex> lock(m_mutex);
  map<string, ServiceEntryListing>::const_iterator entryIterator =
    m_serviceListings.find(name);
  if(entryIterator == m_serviceListings.end()) {
    request.SendResponse(make_tuple(true, "", vector<ServiceEntry>()));
    return;
  }
  const ServiceEntryListing& listing = entryIterator->second;
  request.SendResponse(make_tuple(true, "", listing.m_entries));
}

void ServiceLocatorServlet::OnSubscribeRequest(
    const RequestToken<SubscribeAvailabilityService>& request,
    const string& serviceName) {
  ServiceLocatorChannel* channel = static_cast<ServiceLocatorChannel*>(
    request.GetChannel());
  if(!channel->IsLoggedIn()) {
    request.SendResponse(make_tuple(false, "Not logged in.",
      vector<ServiceEntry>()));
    return;
  }
  boost::lock_guard<boost::mutex> lock(m_mutex);
  ServiceEntryListing& listing = m_serviceListings[serviceName];
  if(find(channel->GetServiceSubscriptions().begin(),
      channel->GetServiceSubscriptions().end(), serviceName) !=
      channel->GetServiceSubscriptions().end()) {
    request.SendResponse(make_tuple(false, "Service already provided.",
      vector<ServiceEntry>()));
    return;
  }
  listing.m_subscribers.push_back(channel);
  channel->SubscribeService(serviceName);
  request.SendResponse(make_tuple(true, "", listing.m_entries));
}

void ServiceLocatorServlet::OnUnsubscribeRequest(
    const RequestToken<UnsubscribeAvailabilityService>& request,
    const string& serviceName) {
  ServiceLocatorChannel* channel = static_cast<ServiceLocatorChannel*>(
    request.GetChannel());
  if(!channel->IsLoggedIn()) {
    request.SendResponse(make_tuple(false, "Not logged in."));
    return;
  }
  boost::lock_guard<boost::mutex> lock(m_mutex);
  ServiceEntryListing& listing = m_serviceListings[serviceName];
  Remove(listing.m_subscribers, channel);
  channel->UnsubscribeService(serviceName);
  request.SendResponse(make_tuple(true, ""));
}

void ServiceLocatorServlet::OnLoadDirectoryEntryRequest(
    const RequestToken<LoadDirectoryEntryService>& request, unsigned int id) {
  ServiceLocatorChannel* channel = static_cast<ServiceLocatorChannel*>(
    request.GetChannel());
  if(!channel->IsLoggedIn()) {
    request.SendResponse(make_tuple(false, "Not logged in.",
      static_cast<DirectoryEntry*>(NULL)));
    return;
  }
  scoped_ptr<DirectoryEntry> directoryEntry;
  DirectoryEntry::Tag tag;
  boost::lock_guard<boost::mutex> lock(m_mutex);
  try {
    tag = m_dataStore->LoadTag(id);
    if(tag.m_type == DirectoryEntry::Type::ACCOUNT) {
      directoryEntry.reset(new Account(tag));
    } else if(tag.m_type == DirectoryEntry::Type::DIRECTORY) {
      vector<DirectoryEntry::Tag> entries =
        m_dataStore->LoadDirectoryEntries(tag.m_id);
      map<unsigned int, Directory::Permission> permissions;
      directoryEntry.reset(new Directory(tag, entries, permissions));
    } else {
      request.SendResponse(make_tuple(false, "Invalid entry.",
        static_cast<DirectoryEntry*>(NULL)));
      return;
    }
  } catch(std::exception& e) {
    request.SendResponse(make_tuple(false, e.what(),
      static_cast<DirectoryEntry*>(NULL)));
    return;
  }
  map<unsigned int, SubscriberEntry>::iterator subscriberIterator =
    m_subscriptions.find(tag.m_id);
  if(subscriberIterator == m_subscriptions.end()) {
    subscriberIterator = m_subscriptions.insert(make_pair(tag.m_id,
      SubscriberEntry(tag))).first;
  }
  SubscriberEntry& subscriberEntry = subscriberIterator->second;
  if(channel->GetDirectoryEntrySubscriptions().find(tag) ==
      channel->GetDirectoryEntrySubscriptions().end()) {
    subscriberEntry.m_subscribers.push_back(channel);
    channel->AddDirectoryEntrySubscription(tag);
  }
  request.SendResponse(make_tuple(true, "", directoryEntry.get()));
}

void ServiceLocatorServlet::OnLoadParentDirectoryRequest(
    const RequestToken<LoadParentDirectoryService>& request, unsigned int id) {
  ServiceLocatorChannel* channel = static_cast<ServiceLocatorChannel*>(
    request.GetChannel());
  if(!channel->IsLoggedIn()) {
    request.SendResponse(make_tuple(false, "Not logged in.",
      DirectoryEntry::Tag()));
    return;
  }
  DirectoryEntry::Tag tag;
  boost::lock_guard<boost::mutex> lock(m_mutex);
  try {
    tag = m_dataStore->LoadParentTag(id);
  } catch(std::exception& e) {
    request.SendResponse(make_tuple(false, e.what(), DirectoryEntry::Tag()));
    return;
  }
  request.SendResponse(make_tuple(true, "", tag));
}

void ServiceLocatorServlet::OnCreateAccountRequest(
    const RequestToken<CreateAccountService>& request,
    const string& name, const DirectoryEntry::Tag& directory,
    const string& password) {
  ServiceLocatorChannel* channel = static_cast<ServiceLocatorChannel*>(
    request.GetChannel());
  if(!channel->IsLoggedIn()) {
    request.SendResponse(make_tuple(false, "Not logged in.",
      DirectoryEntry::Tag()));
    return;
  }
  unsigned int accountId;
  boost::lock_guard<boost::mutex> lock(m_mutex);
  try {
    if(!HasPermission(channel->GetAccount().m_id, directory.m_id,
        Directory::Permission::WRITE)) {
      request.SendResponse(make_tuple(false, "Insufficient permissions.",
        DirectoryEntry::Tag()));
      return;
    }
    if(!m_dataStore->IsNameAvailable(name)) {
      request.SendResponse(make_tuple(false, "Account name unavailable.",
        DirectoryEntry::Tag()));
      return;
    }
    accountId = m_dataStore->CreateAccount(name, directory);
    m_dataStore->AddUnavailableName(name);
    string hashedPassword = ComputeSHA(lexical_cast<string>(accountId) +
      password);
    m_dataStore->SetPassword(accountId, hashedPassword);
  } catch(std::exception& e) {
    request.SendResponse(make_tuple(false, e.what(), DirectoryEntry::Tag()));
    return;
  }
  DirectoryEntry::Tag tag(DirectoryEntry::Type::ACCOUNT, accountId, name);
  request.SendResponse(make_tuple(true, "", tag));
  PublishDirectoryEntryMoved(tag, directory, true);
}

void ServiceLocatorServlet::OnCreateDirectoryRequest(
    const RequestToken<CreateDirectoryService>& request, const string& name,
    const DirectoryEntry::Tag& parent) {
  ServiceLocatorChannel* channel = static_cast<ServiceLocatorChannel*>(
    request.GetChannel());
  if(!channel->IsLoggedIn()) {
    request.SendResponse(make_tuple(false, "Not logged in."));
    return;
  }
  unsigned int directoryId;
  boost::lock_guard<boost::mutex> lock(m_mutex);
  try {
    if(!HasPermission(channel->GetAccount().m_id, parent.m_id,
        Directory::Permission::WRITE)) {
      request.SendResponse(make_tuple(false, "Insufficient permissions."));
      return;
    }
    directoryId = m_dataStore->CreateDirectory(name, parent);
  } catch(std::exception& e) {
    request.SendResponse(make_tuple(false, e.what()));
    return;
  }
  request.SendResponse(make_tuple(true, ""));
  DirectoryEntry::Tag tag(DirectoryEntry::Type::DIRECTORY, directoryId, name);
  PublishDirectoryEntryMoved(tag, parent, true);
}

void ServiceLocatorServlet::OnMoveEntryRequest(
    const RequestToken<MoveEntryService>& request, unsigned int entryId,
    unsigned int directoryId) {
  ServiceLocatorChannel* channel = static_cast<ServiceLocatorChannel*>(
    request.GetChannel());
  if(!channel->IsLoggedIn()) {
    request.SendResponse(make_tuple(false, "Not logged in."));
    return;
  }
  DirectoryEntry::Tag entry(DirectoryEntry::Type::NONE, entryId, "");
  DirectoryEntry::Tag directory(DirectoryEntry::Type::NONE, directoryId, "");
  DirectoryEntry::Tag parent;
  boost::lock_guard<boost::mutex> lock(m_mutex);
  try {
    parent = m_dataStore->LoadParentTag(entry.m_id);
    m_dataStore->MoveEntry(entry.m_id, directory.m_id);
  } catch(std::exception& e) {
    request.SendResponse(make_tuple(false, e.what()));
    return;
  }
  request.SendResponse(make_tuple(true, ""));
  PublishDirectoryEntryMoved(entry, parent, false);
  PublishDirectoryEntryMoved(entry, directory, true);
}

void ServiceLocatorServlet::OnDeleteEntryRequest(
    const RequestToken<DeleteEntryService>& request, unsigned int entryId) {
  ServiceLocatorChannel* channel = static_cast<ServiceLocatorChannel*>(
    request.GetChannel());
  if(!channel->IsLoggedIn()) {
    request.SendResponse(make_tuple(false, "Not logged in."));
    return;
  }
  boost::lock_guard<boost::mutex> lock(m_mutex);
  try {
    DirectoryEntry::Tag tag = m_dataStore->LoadTag(entryId);
    if(!HasPermission(channel->GetAccount().m_id, tag.m_id,
        Directory::Permission::WRITE)) {
      request.SendResponse(make_tuple(false, "Insufficient permissions."));
      return;
    }
    DirectoryEntry::Tag parent = m_dataStore->LoadParentTag(tag.m_id);
    DeleteEntry(tag, parent);
  } catch(std::exception& e) {
    request.SendResponse(make_tuple(false, e.what()));
    return;
  }
  request.SendResponse(make_tuple(true, ""));
}

void ServiceLocatorServlet::OnSetPermissionsRequest(
    const RequestToken<SetPermissionsService>& request, unsigned int accountId,
    unsigned int entryId, Directory::Permission permissions) {
  ServiceLocatorChannel* channel = static_cast<ServiceLocatorChannel*>(
    request.GetChannel());
  if(!channel->IsLoggedIn()) {
    request.SendResponse(make_tuple(false, "Not logged in."));
    return;
  }
  boost::lock_guard<boost::mutex> lock(m_mutex);
  try {
    if(!HasPermission(channel->GetAccount().m_id, accountId,
        Directory::Permission::WRITE) || !HasPermission(
        channel->GetAccount().m_id, entryId, Directory::Permission::WRITE)) {
      request.SendResponse(make_tuple(false, "Insufficient permissions."));
      return;
    }
    m_dataStore->SetPermissions(accountId, entryId, permissions);
  } catch(std::exception& e) {
    request.SendResponse(make_tuple(false, e.what()));
    return;
  }
  request.SendResponse(make_tuple(true, ""));
}

void ServiceLocatorServlet::OnSessionAuthenticationRequest(
    const RequestToken<SessionAuthenticationService>& request,
    const string& sessionId, unsigned int saltId) {
  ServiceLocatorChannel* channel = static_cast<ServiceLocatorChannel*>(
    request.GetChannel());
  if(!channel->IsLoggedIn()) {
    request.SendResponse(make_tuple(false, "Not logged in.",
      DirectoryEntry::Tag()));
    return;
  }
  string salt = lexical_cast<string>(saltId);
  string upperCaseSessionId = to_upper_copy(sessionId);
  boost::lock_guard<boost::mutex> lock(m_mutex);
  for(map<string, ServiceLocatorChannel*>::const_iterator i =
      m_sessions.begin(); i != m_sessions.end(); ++i) {
    string encodedSessionId = ComputeSHA(salt + i->first);
    if(encodedSessionId == upperCaseSessionId) {
      request.SendResponse(make_tuple(true, "", i->second->GetAccount()));
    }
  }
  request.SendResponse(make_tuple(false, "Session not found.",
    DirectoryEntry::Tag()));
}
